﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using PureMVC.Interfaces;
using PureMVC.Patterns;
using SMS.Core.View.Component;
using System.Reflection;
using SMS.Core.Model;
using SMS.Core.Controller.Commands;
using System.Diagnostics;

namespace SMS.Core.View
{
    public class ConnectionMediator : Mediator, IMediator
    {
        #region Constants

        public new const string NAME = "NpgsqlConnectionMediator";

        #endregion

        #region Constructors

        public ConnectionMediator(UserControl viewComponent)
            :base(NAME, viewComponent)
        {
            ConnectionPanel component = (ConnectionPanel)viewComponent;

            // initiate textbox fields behavior
            foreach (TextBox textBox in component.Controls.OfType<TextBox>())
            {
                textBox.TextChanged += new EventHandler(ConnFields_TextChanged);
            }

            // initiate button behavior
            component.ExitButton.Click += new EventHandler(ExitButton_Click);
            component.ConnectButton.Click += new EventHandler(ConnectButton_Click);
            component.DefaultsButton.Click += new EventHandler(DefaultsButton_Click);
            component.ParentForm.AcceptButton = component.ConnectButton;
            component.ParentForm.CancelButton = component.ExitButton;
        }

        #endregion

        #region Public Methods

        public override void OnRemove()
        {
            Facade.RemoveCommand(ModelConstants.Connection.CONNECT);
            Facade.RemoveCommand(ModelConstants.Connection.CONNECTED);
            Facade.RemoveCommand(ModelConstants.Connection.DISCONNECT);
        }

        public override void OnRegister()
        {
            Facade.RegisterCommand(ModelConstants.Connection.CONNECT, typeof(ConnectCommand));
            Facade.RegisterCommand(ModelConstants.Connection.CONNECTED, typeof(ConnectCommand));
            Facade.RegisterCommand(ModelConstants.Connection.DISCONNECT, typeof(DisconnectCommand));
        }

        public override void HandleNotification(INotification notification)
        {
            switch (notification.Name)
            {
                case ModelConstants.Connection.CONNECT:
                    break;
                case ModelConstants.Connection.CONNECTED:
                    //MessageBox.Show("Connected to SMS");
                    //--------------------------------------
                    // Get the ViewComponent's parent form
                    var parent = (ViewComponent as UserControl).ParentForm;

                    // Dispose of the connection panel and unregister its mediator.
                    (ViewComponent as Control).Dispose();
                    Facade.RemoveMediator(this.MediatorName);

                    // Display the login panel on the parent form and dock
                    // the component by filling the form.
                    var loginPanel = new LoginPanel();
                    loginPanel.Dock = DockStyle.Fill;
                    parent.Controls.Add(loginPanel);

                    // Register the loginPanel to its LoginMediator.
                    Facade.RegisterMediator(new LoginMediator(loginPanel));
                    break;
                case ModelConstants.Connection.CONNECT_FAILED:
                    MessageBox.Show(notification.Body.ToString(), // display connection error
                        "Connection Failed",
                        MessageBoxButtons.OK,
                        MessageBoxIcon.Error);
                    break;
            }
        }

        public override IList<string> ListNotificationInterests()
        {
            return new List<string>() 
            {
                ModelConstants.Connection.CONNECT,
                ModelConstants.Connection.CONNECTED,
                ModelConstants.Connection.CONNECT_FAILED
            };
        }
        #endregion

        #region Private & Internal Methods

        #region Event Handlers

        /// <summary>
        /// Toggles the enable/disable property of the <c>ConnectButton</c> property.
        /// If even just one of the fields is either empty or null, the <c>ConnectButton</c>
        /// will be disabled. Otherwise, the button is enabled.
        /// </summary>
        /// <param name="sender">The textbox whose behavior is to be monitored.</param>
        /// <param name="e">Arguments relevant to this event.</param>
        private void ConnFields_TextChanged(object sender, EventArgs e)
        {
            ConnectionPanel component = (ConnectionPanel)ViewComponent;

            var connFields = (ViewComponent as UserControl).Controls.OfType<TextBox>();

            if ((connFields.ToList()[0].Text != "" && connFields.ToList()[0].Text != null) &&
                (connFields.ToList()[1].Text != "" && connFields.ToList()[1].Text != null) &&
                (connFields.ToList()[2].Text != "" && connFields.ToList()[2].Text != null) &&
                (connFields.ToList()[3].Text != "" && connFields.ToList()[3].Text != null) &&
                (connFields.ToList()[4].Text != "" && connFields.ToList()[4].Text != null))
            {
                component.ConnectButton.Enabled = true;
            }
            else
            {
                component.ConnectButton.Enabled = false;
            }
        }

        /// <summary>
        /// Connects to the data source specified by the connection fields.
        /// If the application connects successfully, the user will be brought
        /// to the SMS system domain login dialog. Otherwise, a dialog will be 
        /// shown to indicate that the login was unsuccessful.
        /// </summary>
        /// <param name="sender">The connect button</param>
        /// <param name="e">Button-click event arguments</param>
        private void ConnectButton_Click(object sender, EventArgs e)
        {
            var component = (ConnectionPanel)ViewComponent;
            List<string> connSettings = new List<string> 
            {
                component.ServerField.Text,
                component.PortField.Text,
                component.DatabaseField.Text,
                component.UsernameField.Text,
                component.PasswordField.Text
            };
            // Broadcast that the application is trying to connect to the backend.
            SendNotification(ModelConstants.Connection.CONNECT,
                connSettings);
        }

        /// <summary>
        /// Closes the custom control's parent form by disposing it.
        /// Also forcefully closes the application.
        /// </summary>
        /// <param name="sender">The exit button</param>
        /// <param name="e">Event arguments</param>
        private void ExitButton_Click(object sender, EventArgs e)
        {
            (ViewComponent as UserControl).Parent.Dispose();
            var proc = Process.GetCurrentProcess();
            proc.Kill();
        }

        /// <summary>
        /// Sets all connection fields to the default configuration for the
        /// application. The password is not included for security purposes.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void DefaultsButton_Click(object sender, EventArgs e)
        {
            var nPanel = ViewComponent as ConnectionPanel;
            nPanel.ServerField.Text = "localhost";
            nPanel.PortField.Text = "5432";
            nPanel.DatabaseField.Text = "Shop Management System";
            nPanel.UsernameField.Text = "postgres";
            nPanel.PasswordField.Clear();
        }

        #endregion

        #endregion
    }
}
